package org.qjzn.test.demos.web;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.taobao.api.ApiException;
import com.taobao.api.FileItem;
import org.qjzn.test.demos.web.domain.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
public class BasicController {

    private static final Logger log = LoggerFactory.getLogger(BasicController.class);
    @Value("${app.downloadUrl}")
    private String downloadUrl;
    private static final String corpid="your corpid";
    private static final String appKey="your appKey";
    private static final String appSecret="your appSecret";
    private static final Long agentId= 12345678L;
    // 定义基础目录
    private static final String BASE_DIRECTORY = "C:/licence/";
    @Value("${dd.msgUserId}")
    private String msgUserId;
    @Value("${dd.commentUserId}")
    private String commentUserId;
    @PostMapping("/test")
    public R test(@RequestBody AuthorizationProductRequest request) throws Exception {
        List<String> errorMsg=new ArrayList<>();
        AuthorizationProductResponse response=new AuthorizationProductResponse();

        //授权目的
        response.setPurpose(request.getAuthorizationPurpose().getLabel());

        // 授权产品
        if(request.getAuthorizationProduct().getLabel().equals("QJCAM")){
            response.setProduct(request.getAuthorizationProduct().getLabel());
        }else{
            errorMsg.add("暂不支持UItraPP授权");
        }

        // 客户单位名称
        response.setOrgName(request.getCustomerCompanyName());

        // 授权类型
        if(request.getAuthorizationType().getLabel().equals("浮动")){
            errorMsg.add("暂不支持浮动授权");
        }else{
            response.setLicType(request.getAuthorizationType().getLabel());
        }

        // 授权天数
        if(request.getAuthorizationDays().getLabel().equals("永久")){
            errorMsg.add("授权失败: 授权天数不能为永久,最长不超过365天");
            response.setLicDays(9999);
        }else if(request.getAuthorizationDays().getLabel().equals("其它")){
            if(request.getOtherAuthorizationDays()>365){
                errorMsg.add("授权失败: 授权天数不最长不超过365天");
            }
            response.setLicDays(request.getOtherAuthorizationDays());
        }else{
            response.setLicDays(Integer.parseInt(request.getAuthorizationDays().getLabel().replace("天", "")));
        }

        // 授权明细表
        List<AuthorizationDetail> authorizationDetails = getAuthorizationDetails(request);
        response.setAuthorizationDetails(authorizationDetails);

        // 授权项选择模式
        response.setLicSelectMode(request.getAuthorizationSelectionMode().getLabel());
        List<String> licModules = new ArrayList<>(); // 授权模块
        List<String> licCasingFeats = new ArrayList<>(); // 通用功能模块
        List<String> licTurboFeats = new ArrayList<>(); // 透平功能模块
        List<String> licInspectFeats = new ArrayList<>(); // 测量功能模块
        List<String> licPcdFeats = new ArrayList<>(); // PCD功能模块
        List<String> licFitFeats = new ArrayList<>(); // 自适应功能模块
        List<String> licOtherFeats = new ArrayList<>(); // 其他功能模块

        if (!CollectionUtils.isEmpty(request.getDetailedProductSelections())) {
            List<AuthorizationProductRequest.SelectField> detailedProductSelections = request.getDetailedProductSelections();
            for (AuthorizationProductRequest.SelectField detailedProductSelection : detailedProductSelections) {
                licModules.add(detailedProductSelection.getLabel());
                switch (detailedProductSelection.getLabel()) {
                    case "通用":
                        if (!CollectionUtils.isEmpty(request.getGeneralProductModules())) {
                            for (AuthorizationProductRequest.SelectField generalProductModule : request.getGeneralProductModules()) {
                                licCasingFeats.add(generalProductModule.getLabel());
                            }
                        }
                        break;
                    case "透平":
                        if (!CollectionUtils.isEmpty(request.getTurbineProductModules())) {
                            for (AuthorizationProductRequest.SelectField turbineProductModule : request.getTurbineProductModules()) {
                                licTurboFeats.add(turbineProductModule.getLabel());
                            }
                        }
                        break;
                    case "测量":
                        if (!CollectionUtils.isEmpty(request.getMeasurementProductModules())) {
                            for (AuthorizationProductRequest.SelectField measurementProductModule : request.getMeasurementProductModules()) {
                                licInspectFeats.add(measurementProductModule.getLabel());
                            }
                        }
                        break;
                    case "PCD":
                        if (!CollectionUtils.isEmpty(request.getPcdProductModules())) {
                            for (AuthorizationProductRequest.SelectField pcdProductModule : request.getPcdProductModules()) {
                                licPcdFeats.add(pcdProductModule.getLabel());
                            }
                        }
                        break;
                    case "自适应产品":
                        if (!CollectionUtils.isEmpty(request.getAdaptiveProductModules())) {
                            for (AuthorizationProductRequest.SelectField adaptiveProductModule : request.getAdaptiveProductModules()) {
                                licFitFeats.add(adaptiveProductModule.getLabel());
                            }
                        }
                        break;
                    case "其他":
                        if (!CollectionUtils.isEmpty(request.getOtherModules())) {
                            for (AuthorizationProductRequest.SelectField otherModule : request.getOtherModules()) {
                                licOtherFeats.add(otherModule.getLabel());
                            }
                        }
                        break;
                }
            }
        }

        response.setLicModules(licModules);
        response.setLicCasingFeats(licCasingFeats);
        response.setLicTurboFeats(licTurboFeats);
        response.setLicInspectFeats(licInspectFeats);
        response.setLicPcdFeats(licPcdFeats);
        response.setLicFitFeats(licFitFeats);
        response.setLicOtherFeats(licOtherFeats);

        response.setComment(request.getRemarks());
        String accessToken=getAccessToken();
        String userId = getUserId(accessToken,request.getInstanceId());
        //申请人姓名
        String applyName = getUserNameById(userId, accessToken);
        response.setApplicat(applyName);
        response.setFormID(request.getInstanceId());
        response.setLicFilePath("C:/licence/" + request.getInstanceId()+"/result");

        // 生成文件路径
        String filePathRequest = "C:/licence/" + request.getInstanceId() +"/request/"+ "request.json";
        String filePathResult = "C:/licence/" + request.getInstanceId() +"/result";
        // 将 JSON 写入文件以便LicenseBuilder.exe调用
        createJsonFile(response,filePathRequest,filePathResult);

        //调用LicenseBuilder.exe生成result.json和授权文件
        String exeUrl="Builder.exe";
        ProcessBuilder processBuilder = new ProcessBuilder(exeUrl, "--auto-gen", filePathRequest);
        Process process = processBuilder.start();
        int exitCode = process.waitFor();

        // 构建文件路径
        String resultJsonPath = BASE_DIRECTORY + sanitizePath(request.getInstanceId()) + "/result/result.json";
        // 读取 result.json 文件内容
        String jsonString = new String(Files.readAllBytes(Paths.get(resultJsonPath)));
        LicenseResponse licenseResponse = JSON.parseObject(jsonString, LicenseResponse.class);
        //status=0表示授权文件至少有一个没有生成成功。
        int status=licenseResponse.getSuccNum()==licenseResponse.getSumNum()?1:0;
        for (Result result : licenseResponse.getRes()) {
            if (result.getSucc()==0) {
                errorMsg.add(result.getErrmsg());
            }
        }
        String baseUrl = "dingtalk://dingtalkclient/page/link?pc_slide=true&redirect_type=jump&url=";
        String encodedUrl = "https%3A%2F%2Faflow.dingtalk.com%2Fdingtalk%2Fpc%2Fquery%2Fpchomepage.htm%3Fcorpid%3D" + corpid +
                "%23%2Fapproval%3FprocInstId%3D" + request.getInstanceId();
        if(status==0 && licenseResponse.getSuccNum()>0){
            sendComment(accessToken,request.getInstanceId(),commentUserId,
                    downloadUrl+"?instanceId="+request.getInstanceId(),
                    "授权文件部分生成成功，下方链接为成功部分文件，错误消息已通知胡利利",status,1);
            corpConversationSend(accessToken,userId,baseUrl+encodedUrl,"你提交的软件授权申请通过了,但部分授权文件生成失败（已通知胡利利）点击下方链接跳转对应审批单，在评论区点击链接即可下载授权文件",status);
            corpConversationSend(accessToken,msgUserId,baseUrl+encodedUrl,"部分授权文件生成失败,错误原因:["+ errorMsg +"],点击下方链接跳转对应审批单",status);

        }else if(status==1){
            sendComment(accessToken,request.getInstanceId(),commentUserId,
                    downloadUrl+"?instanceId="+request.getInstanceId(),"文件全部生成成功",status,1);
            corpConversationSend(accessToken,userId,baseUrl+encodedUrl,"你提交的软件授权申请通过了,点击下方链接跳转对应审批单，在评论区点击链接即可下载授权文件",status);
        }else if(status==0 && licenseResponse.getSuccNum()==0){
            sendComment(accessToken,request.getInstanceId(),commentUserId,
                    downloadUrl+"?instanceId="+request.getInstanceId(),"文件全部生成失败，错误消息已通知胡利利",status,0);
            corpConversationSend(accessToken,userId,baseUrl+encodedUrl,"你提交的软件授权申请通过了,但授权文件全部生成失败（已通知胡利利），点击下方链接跳转对应审批单",status);
            corpConversationSend(accessToken,msgUserId,baseUrl+encodedUrl,"全部授权文件生成失败,错误原因:["+ errorMsg +"],点击下方链接跳转对应审批单",status);
        }
        return R.ok();
    }
    /**
     * @description:获取申请人姓名
     * @author: 杨祥
     * @date: 2025/2/17 9:30
     * @param: [java.lang.String, java.lang.String]
     * @return: java.lang.String
    **/
    private  String getUserNameById(String userId, String access_token) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
        OapiV2UserGetRequest req = new OapiV2UserGetRequest();
        req.setUserid(userId);
        req.setLanguage("zh_CN");
        OapiV2UserGetResponse rsp = client.execute(req, access_token);
        return rsp.getResult().getName();
    }

    /**
     * @description:通过实例id获取审批发起人userId
     * @author: 杨祥
     * @date: 2025/2/18 16:20
     * @param: [java.lang.String, java.lang.String]
     * @return: java.lang.String
    **/
    private String getUserId(String accessToken, String instanceId) throws Exception {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/get");
        OapiProcessinstanceGetRequest req = new OapiProcessinstanceGetRequest();
        req.setProcessInstanceId(instanceId);
        OapiProcessinstanceGetResponse rsp = client.execute(req, accessToken);
        return rsp.getProcessInstance().getOriginatorUserid();
    }
    // 授权明细表
    private  List<AuthorizationDetail> getAuthorizationDetails(AuthorizationProductRequest request) {
        List<AuthorizationDetail> authorizationDetails =new ArrayList<>();
        if(!CollectionUtils.isEmpty(request.getAuthorizationDetails())){
            for(AuthorizationProductRequest.AuthorizationDetail detail: request.getAuthorizationDetails()){
                AuthorizationDetail temp=new AuthorizationDetail();
                temp.setCustName(detail.getCustomerName());

                temp.setNeedDongle(1);
                if(detail.getEncryptionLock().getLabel().equals("否")){
                    temp.setComputerId(detail.getMachineCode());//机器码
                    temp.setNeedDongle(0);
                }

                temp.setConnMachine("否");
                if(detail.getLinkedMachineDetail().getLabel().equals("是")){
                    temp.setMachineId(detail.getMachineToolCode());
                    temp.setConnMachine("是");
                    temp.setCnc(detail.getCncSystem());
                } else if(detail.getLinkedMachineDetail().getLabel().equals("连接任意机床")){
                    temp.setConnMachine("连接任意机床");
                    if(detail.getCncSystem()!=null){
                        temp.setCnc(detail.getCncSystem());
                    }
                }
                authorizationDetails.add(temp);
            }
        }
        return authorizationDetails;
    }

    /**
     * @description:将JSON数据格式化并保存到文件中
     * @author: 杨祥
     * @date: 2025/2/17 10:28
     * @param: [java.lang.Object, java.lang.String, java.lang.String]
     * @return: boolean
    **/
    public  boolean createJsonFile(Object jsonData, String filePathRequest,String filePathResult) {
        String content = JSON.toJSONString(jsonData, SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,SerializerFeature.WriteNullStringAsEmpty,SerializerFeature.WriteMapNullValue);
        // 标记文件生成是否成功
        boolean flag = true;
        // 生成json格式文件
        try {
            // 保证创建一个新文件
            File file = new File(filePathRequest);
            File file1 = new File(filePathResult); //以某路径实例化一个File对象
            if (!file1.exists()){ //如果不存在
                boolean dr = file1.mkdirs(); //创建目录
            }
            if (!file.getParentFile().exists()) { // 如果父目录不存在，创建父目录
                file.getParentFile().mkdirs();
            }
            if (file.exists()) { // 如果已存在,删除旧文件
                file.delete();
            }
            file.createNewFile();
            // 将格式化后的字符串写入文件
            Writer write = new OutputStreamWriter(Files.newOutputStream(file.toPath()), "UTF-8");
            write.write(content);
            write.flush();
            write.close();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    public   com.aliyun.dingtalkoauth2_1_0.Client createClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }
    /**
     * @description:获取accessToken
     * @author: 杨祥
     * @date: 2025/2/17 9:32
     * @param: []
     * @return: java.lang.String
    **/
    public   String getAccessToken() throws Exception {
        com.aliyun.dingtalkoauth2_1_0.Client client = createClient();
        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
                .setAppKey(appKey)
                .setAppSecret(appSecret);
        return client.getAccessToken(getAccessTokenRequest).getBody().getAccessToken();
    }
    /**
     * @description:获取文件在钉钉的mediaId,用于后续发送文件到个人。,licFileUrl为全路径包括文件后缀。
     * @author: 杨祥
     * @date: 2025/2/14 10:36
     * @param: [java.lang.String]
    **/
    private static String getUploadMediaId(String accessToken,String licFileUrl) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/media/upload");
        OapiMediaUploadRequest req = new OapiMediaUploadRequest();
        req.setType("file");
        // 要上传的媒体文件
        FileItem item = new FileItem(licFileUrl);
        req.setMedia(item);
        OapiMediaUploadResponse rsp = client.execute(req, accessToken);
        return rsp.getMediaId();
    }
    /**
     * @description:发送消息到钉钉个人
     * @author: 杨祥
     * @date: 2025/2/14 10:47
     * @param: [java.lang.String, java.lang.String]
     * @return: void
    **/
    public  void corpConversationSend(String accessToken,String userId,String linkUrl,String msgDetail,int status) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(agentId);
        request.setUseridList(userId);
        request.setToAllUser(false);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(msgDetail+linkUrl);
        request.setMsg(msg);
        OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(request, accessToken);
        log.info("消息通知到个人 response:{}",rsp.getErrcode());
    }

    /**
     * @description:发送审批评论
     * @author: 杨祥
     * @date: 2025/2/18 9:20
     * @param: [java.lang.String, java.lang.String, java.lang.String, java.lang.String]
     * @return: java.lang.Boolean
    **/
    private Boolean sendComment(String access_token,String instanceId,String userId,String url,
                                String msg,int status,int isUrl) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/process/instance/comment/add");
        OapiProcessInstanceCommentAddRequest req = new OapiProcessInstanceCommentAddRequest();
        OapiProcessInstanceCommentAddRequest.AddCommentRequest commentRequest = new OapiProcessInstanceCommentAddRequest.AddCommentRequest();
        commentRequest.setProcessInstanceId(instanceId);
        commentRequest.setCommentUserid(userId);
        if(isUrl==1){
            commentRequest.setText(msg+url);
        }else{
            commentRequest.setText(msg);
        }
        req.setRequest(commentRequest);
        OapiProcessInstanceCommentAddResponse rsp = client.execute(req, access_token);
        return rsp.getSuccess();
    }
    @GetMapping("/download")
    public ResponseEntity<Resource> downloadFile(@RequestParam String instanceId) throws IOException {
        // 构建文件路径
        String resultJsonPath = BASE_DIRECTORY + sanitizePath(instanceId) + "/result/result.json";
        File resultJsonFile = new File(resultJsonPath);

        if (!resultJsonFile.exists() || !resultJsonFile.isFile()) {
            return ResponseEntity.notFound().build();
        }

        // 读取 result.json 文件内容
        String jsonString = new String(Files.readAllBytes(Paths.get(resultJsonPath)));
        LicenseResponse licenseResponse = JSON.parseObject(jsonString, LicenseResponse.class);

        // 提取所有成功的文件路径
        List<String> filePaths = new ArrayList<>();
        for (Result result : licenseResponse.getRes()) {
            if (result.getSucc() == 1 && result.getFile() != null) {
                filePaths.add(result.getFile());
            }
        }
        if (filePaths.isEmpty()) {
            return ResponseEntity.badRequest().body(null);
        }
        Resource resource;
        HttpHeaders headers = new HttpHeaders();
        if (filePaths.size() == 1) {
            // 如果只有一个文件，直接返回该文件
            File singleFile = new File(filePaths.get(0));
            resource = new FileSystemResource(singleFile);
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + singleFile.getName() + "\"");
        } else {
            // 如果有多个文件，检查是否存在已存在的 ZIP 文件
            String zipFileName = "resultFile" + ".zip";
            Path zipFilePath = Paths.get(BASE_DIRECTORY + sanitizePath(instanceId) + "/result/" + zipFileName);
            File existingZipFile = zipFilePath.toFile();
            if (existingZipFile.exists() && existingZipFile.isFile()) {
                resource = new FileSystemResource(existingZipFile);
            } else {
                // 创建新的 ZIP 文件
                try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zipFilePath))) {
                    for (String filePath : filePaths) {
                        File fileToZip = new File(filePath);
                        FileInputStream fis = new FileInputStream(fileToZip);
                        ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
                        zos.putNextEntry(zipEntry);
                        byte[] bytes = new byte[1024];
                        int length;
                        while ((length = fis.read(bytes)) >= 0) {
                            zos.write(bytes, 0, length);
                        }
                        fis.close();
                    }
                }
                resource = new FileSystemResource(zipFilePath.toFile());
            }
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + zipFileName + "\"");
        }

        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);
    }
    // 基本路径清理函数 移除任何可能导致路径遍历的字符
    private String sanitizePath(String path) {
        return path.replaceAll("[^a-zA-Z0-9-_]", "");
    }
}
